﻿using System;
using Habanero.Base;
using Habanero.BO;
using Habanero.BO.ClassDefinition;
using Habanero.BO.Loaders;
using Habanero.UI.Base;
using Habanero.UI.Win;
using NUnit.Framework;
using Rhino.Mocks;
using UseCaseManager.BO;
using UseCaseManager.Test.BO;
using UseCaseManager.UI;

namespace UseCaseManager.Test.UI
{
    [TestFixture]
    public class TestUseCaseCompletedSelectorControl
    {
        [TestFixtureSetUp]
        public void SetupTestFixture()
        {
            //Executes once for all tests in this fixture
            ClassDef.ClassDefs.Clear();
            ClassDef.LoadClassDefs(new XmlClassDefsLoader(BOBroker.GetClassDefsXml(), new DtdLoader()));
        }

        [SetUp]
        public void TestSetup()
        {
            //Test Setup Runs prior to each test in this fixture executing.
            BORegistry.DataAccessor = new DataAccessorInMemory();
            TestUtils.ClearAllTables();
            BusinessObjectManager.Instance.ClearLoadedObjects();
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GlobalUIRegistry.ControlFactory = new ControlFactoryWin();
        }

        [Test]
        public void Test_CreateUseCaseCompletedSelectorControl_WithNoDrop()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            UseCaseCompletedSelectorControl selector = new UseCaseCompletedSelectorControl();
            //---------------Test Result -----------------------
            Assert.IsNotNull(selector);
        }
        
        [Test]
        public void Test_CreateUseCaseCompletedSelectorControl()
        {
            //---------------Set up test pack-------------------
            Drop drop = TestUtilsDrop.CreateUnsavedValidDrop();
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            UseCaseCompletedSelectorControl selector = new UseCaseCompletedSelectorControl(drop);
            //---------------Test Result -----------------------
            Assert.IsNotNull(selector);
            Assert.IsNotNull(selector.DropCompletedIn);
            Assert.IsNotNull(selector.UseCaseMultiSelector);
            Assert.IsNotNull(selector.SaveButton);
            Assert.IsNotNull(selector.ExportCompletionStatusButton);
        }

        [Test]
        public void Test_CreateUseCaseCompletedSelectorControl_DropNull()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                new UseCaseCompletedSelectorControl(null);
                Assert.Fail("expected ArgumentNullException");
            }
            //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("drop", ex.ParamName);
            }
        }
        
        [Test]
        public void Test_CreateUseCaseSelectorControl_BorderLayoutManagerSetup()
        {
            //---------------Set up test pack-------------------
            Drop drop = TestUtilsDrop.CreateUnsavedValidDrop();
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            const int expectedWidth = 223;
            const int expectedHeight = 355;
            const int defaultButtonHeight = 23;
            UseCaseCompletedSelectorControl selector = new UseCaseCompletedSelectorControl(drop) { Width = expectedWidth, Height = expectedHeight };
            //---------------Test Result -----------------------
            Assert.AreEqual(expectedWidth, selector.UseCaseMultiSelector.Width);
            Assert.AreEqual(defaultButtonHeight, selector.SaveButton.Height);
            Assert.AreEqual(0, selector.UseCaseMultiSelector.Top);
            Assert.AreEqual(expectedHeight - selector.SaveButton.Height - 10, selector.UseCaseMultiSelector.Height);
        }

        [Test]
        public void Test_UseCaseCompletedSelectorControl_ChangeSize_MultiSelectorChangesSize()
        {
            //---------------Set up test pack-------------------
            Drop drop = TestUtilsDrop.CreateUnsavedValidDrop();
            UseCaseCompletedSelectorControl selector = new UseCaseCompletedSelectorControl(drop) { Width = 544, Height = 877 };
            const int expectedWidth = 223;
            const int expectedHeight = 355;
            const int defaultButtonHeight = 23;
            //---------------Assert Precondition----------------
            Assert.AreNotEqual(expectedWidth, selector.UseCaseMultiSelector.Width);
            Assert.AreEqual(defaultButtonHeight, selector.SaveButton.Height);
            Assert.AreEqual(0, selector.UseCaseMultiSelector.Top);
            Assert.AreNotEqual(expectedHeight - selector.SaveButton.Height - 10, selector.UseCaseMultiSelector.Height);
            //---------------Execute Test ----------------------
            selector.Width = expectedWidth;
            selector.Height = expectedHeight;
            //---------------Test Result -----------------------
            Assert.AreEqual(expectedWidth, selector.UseCaseMultiSelector.Width);
            Assert.AreEqual(defaultButtonHeight, selector.SaveButton.Height);
            Assert.AreEqual(0, selector.UseCaseMultiSelector.Top);
            Assert.AreEqual(expectedHeight - selector.SaveButton.Height - 10, selector.UseCaseMultiSelector.Height);
        }

        [Test]
        public void Test_CreateUseCaseCompletedSelectorControl_BorderLayoutManagerSetup_WithNoDrop()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            const int expectedWidth = 223;
            const int expectedHeight = 355;
            const int defaultButtonHeight = 23;
            UseCasesSelectorControl selector = new UseCasesSelectorControl { Width = expectedWidth, Height = expectedHeight };
            //---------------Test Result -----------------------
            Assert.AreEqual(expectedWidth, selector.UseCaseMultiSelector.Width);
            Assert.AreEqual(defaultButtonHeight, selector.SaveButton.Height);
            Assert.AreEqual(0, selector.UseCaseMultiSelector.Top);
            Assert.AreEqual(expectedHeight - selector.SaveButton.Height - 10, selector.UseCaseMultiSelector.Height);
        }


        [Test]
        public void Test_Criteria_GetsCorrectDrops()
        {
            //---------------Set up test -----------------------

            Drop dropCurrent = TestUtilsDrop.CreateUnsavedDrop_WUseCases(4);
            Drop dropPast = TestUtilsDrop.CreateUnsavedDrop_WUseCases(2);
            Drop dropFuture = TestUtilsDrop.CreateUnsavedDrop_WUseCases(1);
            dropPast.EndDate = DateTime.Now.AddDays(-3);
            dropCurrent.EndDate = DateTimeNow.Value;
            dropFuture.EndDate = DateTime.Now.AddDays(3);
            dropPast.Save();
            dropCurrent.Save();
            dropFuture.Save();
            Criteria criteriaAllDropsUpToDrop = new Criteria("EndDate", Criteria.ComparisonOp.LessThanEqual, dropCurrent.EndDate);
            //---------------Assert pre conditions -------------
            //---------------Execute Test ----------------------
            BusinessObjectCollection<Drop> dropCol = Broker.GetBusinessObjectCollection<Drop>(criteriaAllDropsUpToDrop);
            //---------------Test Result -----------------------
            Assert.AreEqual(2,dropCol.Count);
        }


        [Test]
        public void Test_ListAvailableOptions_LoadsBlankListOfIncompleteUseCases_OneDrop()
        {
            //---------------Set up test pack-------------------
            Drop drop = TestUtilsDrop.CreateUnsavedDrop_WUseCases(TestUtils.GetRandomInt(0,6));
            foreach (UseCase useCase in drop.UseCases)
            {
                useCase.CompletedInDropID = drop.DropID;
            }
            drop.Save();
            drop.UseCases.SaveAll();
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            UseCaseCompletedSelectorControl selector = new UseCaseCompletedSelectorControl(drop);
            //---------------Test Result -----------------------
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            int expectedNumberOfCompletedUseCases = drop.UseCases.Count;
            Assert.AreEqual(expectedNumberOfCompletedUseCases, multiSelector.AllOptions.Count);
            Assert.AreEqual(expectedNumberOfCompletedUseCases,multiSelector.SelectedOptions.Count);
            int numOfIncompleteUseCases = multiSelector.AllOptions.Count - multiSelector.SelectedOptions.Count;
            Assert.AreEqual(0,numOfIncompleteUseCases);
        }

        [Test]
        public void Test_ListAvailableOptions_LoadsBlankListOfIncompleteUseCases_ManyDrops()
        {
            //---------------Set up test pack-------------------
            Drop drop = TestUtilsDrop.CreateUnsavedDrop_WUseCases(3);
            drop.UseCases[0].CompletedInDropID = drop.DropID;
            drop.UseCases[1].CompletedInDropID = drop.DropID;
            drop.UseCases[2].CompletedInDropID = drop.DropID;
            Drop drop2 = TestUtilsDrop.CreateUnsavedDrop_WUseCases(2);
            drop2.UseCases[0].CompletedInDropID = drop2.DropID;
            drop2.UseCases[1].CompletedInDropID = drop2.DropID;
            //Manipulate EndDates to insure correct order
            drop.EndDate = DateTime.Now.AddDays(1);
            drop2.EndDate = DateTime.Now.AddDays(3);
            drop.Save();
            drop2.Save();
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            UseCaseCompletedSelectorControl selector = new UseCaseCompletedSelectorControl(drop2);
            //---------------Test Result -----------------------
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            //4= 3 that belong to drop2+1 incomplete from drop
            Assert.AreEqual(2, multiSelector.AllOptions.Count);
            Assert.AreEqual(2, multiSelector.SelectedOptions.Count);
            int numOfIncompleteUseCases = multiSelector.AllOptions.Count - multiSelector.SelectedOptions.Count;
            Assert.AreEqual(0, numOfIncompleteUseCases);
        }

        [Test]
        public void Test_ListAvailableOptions_LoadsListOfIncompleteUseCases_FromPreviousDrop()
        {
            //---------------Set up test pack-------------------
            Drop drop = TestUtilsDrop.CreateUnsavedDrop_WUseCases(3);
            drop.UseCases[0].CompletedInDropID = null;
            drop.UseCases[1].CompletedInDropID = drop.DropID;
            drop.UseCases[2].CompletedInDropID = null;
            drop.Save();
            drop.UseCases.SaveAll();
            Drop drop2 = TestUtilsDrop.CreateUnsavedDrop_WUseCases(2);
            drop2.UseCases[0].CompletedInDropID = drop2.DropID;
            drop2.UseCases[1].CompletedInDropID = null;
            drop2.Save();
            drop2.UseCases.SaveAll();
            //2 just floating about in the BO- unassigned and incomplete
            TestUtilsUseCase.CreateUnsavedValidUseCase().Save();
            TestUtilsUseCase.CreateUnsavedValidUseCase().Save();
            //Manipulate EndDates to insure correct order
            drop.EndDate = DateTime.Now.AddDays(1);
            drop2.EndDate = DateTime.Now.AddDays(7);
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            UseCaseCompletedSelectorControl selector = new UseCaseCompletedSelectorControl(drop2);
            //---------------Test Result -----------------------
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            //4 = 1 complete in drop2 + 1 incomplete in drop2 + 2 incomplete from drop
            Assert.AreEqual(4, multiSelector.AllOptions.Count);
            Assert.AreEqual(1, multiSelector.SelectedOptions.Count);
            int numOfIncompleteUseCases = multiSelector.AllOptions.Count - multiSelector.SelectedOptions.Count;
            Assert.AreEqual(3, numOfIncompleteUseCases);
        }

        [Test]
        public void Test_SetDropToNull()
        {
            //---------------Set up test pack-------------------
            Drop drop = CreateDrop_SixUseCases_TwoAssociatedWithDrop_OneWithAnotherDrop();
            drop.UseCases[0].CompletedInDropID = drop.DropID;
            drop.UseCases[1].CompletedInDropID = drop.DropID;
            const int numUseCasesCompletedThisDrop = 2;
            drop.Save();
            drop.UseCases.SaveAll();
            UseCaseCompletedSelectorControl selector = new UseCaseCompletedSelectorControl();
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            selector.DropCompletedIn = drop;
            //---------------Assert Precondition----------------
            Assert.AreEqual(numUseCasesCompletedThisDrop, multiSelector.SelectedOptionsListBox.Items.Count);
            //---------------Execute Test ----------------------
            selector.DropCompletedIn = null;
            //---------------Test Result -----------------------
            Assert.IsNull(selector.DropCompletedIn);
            Assert.AreEqual(0, multiSelector.SelectedOptionsListBox.Items.Count);
            Assert.AreEqual(0, multiSelector.AllOptions.Count);
            Assert.AreEqual(0, multiSelector.AvailableOptionsListBox.Items.Count);
        }

        [Test]
        public void Test_Save_NoChangeToSelectedOptions()
        {
            //---------------Set up test pack-------------------
            Drop drop = CreateDrop_SixUseCases_TwoAssociatedWithDrop_OneWithAnotherDrop();
            drop.UseCases[0].CompletedInDropID = drop.DropID;
            drop.UseCases[1].CompletedInDropID = drop.DropID;
            drop.Save();
            drop.UseCases.SaveAll();
            UseCaseCompletedSelectorControl selector = new UseCaseCompletedSelectorControl();
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            selector.DropCompletedIn = drop;
            multiSelector.SelectedOptionsListBox.SelectedIndex = 0;
            MockRepository mockRepository = new MockRepository();
            IControlFactory controlFactory = mockRepository.DynamicMock<IControlFactory>();
            GlobalUIRegistry.ControlFactory = controlFactory;
            mockRepository.ReplayAll();
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            selector.SaveButton.PerformClick();
            //---------------Test Result -----------------------
            AssertAllUseCasesHaveCompletedInDropIDSavedOrNull(drop);
            controlFactory.AssertWasCalled(factory => 
                factory.ShowMessageBox("Selected Options marked as completed",
                    "Marked as Completed", MessageBoxButtons.OK, MessageBoxIcon.None));
        }

        [Test]
        public void Test_Save_OneCompleted_OneIncomplete()
        {
            //---------------Set up test pack-------------------
            UseCase useCase = TestUtilsUseCase.CreateUnsavedValidUseCase();
            UseCase useCase2 = TestUtilsUseCase.CreateUnsavedValidUseCase();
            Drop drop = TestUtilsDrop.CreateUnsavedValidDrop();
            drop.UseCases.Add(useCase);
            drop.UseCases.Add(useCase2);
            useCase.CompletedInDropID = drop.DropID;
            useCase2.CompletedInDropID = drop.DropID;
            drop.Save();
            const int numUseCasesNotCompletedInThisDrop = 1;
            const int numUseCasesCompletedInThisDrop = 1;
            const int numUseCasesAssignedToThisDrop = 2;
            UseCaseCompletedSelectorControl selector = new UseCaseCompletedSelectorControl();
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            selector.DropCompletedIn = drop;
            MockRepository mockRepository = new MockRepository();
            IControlFactory controlFactory = mockRepository.DynamicMock<IControlFactory>();
            GlobalUIRegistry.ControlFactory = controlFactory;
            mockRepository.ReplayAll();
            //---------------Assert Precondition----------------
            Assert.AreEqual(numUseCasesAssignedToThisDrop,numUseCasesCompletedInThisDrop+numUseCasesNotCompletedInThisDrop);
            Assert.AreEqual(numUseCasesAssignedToThisDrop, multiSelector.AllOptions.Count);
            //---------------Execute Test ----------------------
            selector.SaveButton.PerformClick();
            //---------------Test Result -----------------------
            AssertAllUseCasesHaveCompletedInDropIDSavedOrNull(drop);
            AssertAllUseCasesHaveCompletedInDropIDSavedOrNull(drop);
            controlFactory.AssertWasCalled(factory =>
                factory.ShowMessageBox("Selected Options marked as completed",
                    "Marked as Completed", MessageBoxButtons.OK, MessageBoxIcon.None));
        }

        private static void AssertAllUseCasesHaveCompletedInDropIDSavedOrNull(Drop drop)
        {
            foreach (UseCase useCase in drop.UseCases.Clone())
            {
                IBOProp completedInDropIDProp = useCase.Props["CompletedInDropID"];
                IBOProp dropIDProp = useCase.Props["DropID"];
                if (!completedInDropIDProp.PropertyValueString.Equals(dropIDProp.PropertyValueString))
                {
                    Assert.AreEqual(null, completedInDropIDProp.Value);
                }
                else
                Assert.AreEqual(drop.DropID, completedInDropIDProp.Value);
            }
        }

        private static Drop CreateDrop_SixUseCases_TwoAssociatedWithDrop_OneWithAnotherDrop()
        {
            Drop drop = TestUtilsDrop.CreateUnsavedValidDrop();
            drop.UseCases.Add(TestUtilsUseCase.CreateSavedUseCase());
            drop.UseCases.Add(TestUtilsUseCase.CreateSavedUseCase());
            drop.Save();
            drop.UseCases.SaveAll();
            Drop anotherDrop = TestUtilsDrop.CreateUnsavedValidDrop();
            anotherDrop.UseCases.Add(TestUtilsUseCase.CreateSavedUseCase());
            anotherDrop.Save();
            anotherDrop.UseCases.SaveAll();
            TestUtilsUseCase.CreateUnsavedValidUseCase().Save();
            TestUtilsUseCase.CreateUnsavedValidUseCase().Save();
            TestUtilsUseCase.CreateUnsavedValidUseCase().Save();
            return drop;
        }
    }
}
